using System;
using System.IO;
using System.Text;

using System.Runtime.InteropServices;
using System.Threading;

namespace System.IO
{
	/// <summary>
	/// The LatentStreamReader class is to be used to read from a stream whose incoming data is
	/// not always readily available. This class should only be used in a multi-threaded environment,
	/// as it will cause the current thread to sleep as neccesary until the data it seeks is available.
	/// </summary>
	/// <remarks>I believe the term is called "blocking" - but this class doesn't want the underlying
	/// stream to use blocking.</remarks>
	public class LatentStreamReader : System.IO.TextReader
	{
		#region Private Variables
		private bool _checkPreamble;
 
		private bool _detectEncoding;
 
		private bool _isBlocked;
 
		private int _maxCharsPerBuffer;
 
		private byte[] _preamble;
 
		private byte[] byteBuffer;
 
		private int byteLen;
 
		private char[] charBuffer;
 
		private int charLen;
 
		private int charPos;
 
		private Decoder decoder;
 
		internal const int DefaultBufferSize = 0x400;
 
		private const int DefaultFileStreamBufferSize = 0x1000;
 
		private Encoding encoding;
 
		private const int MinBufferSize = 0x80;
		
		private bool _IsNetWrapper;
		private bool _IsPSWrapper;
		private bool _Bailout;
		private bool _IsLinefeedPending;
 
		private Stream stream;
		#endregion

		#region Constructors
		internal LatentStreamReader()
		{
		}
 
		public LatentStreamReader(Stream stream) : this(stream, Encoding.UTF8, true, 0x400)
		{
		}
 
		public LatentStreamReader(string path) : this(path, Encoding.UTF8, true, 0x400)
		{
		}
 
		public LatentStreamReader(Stream stream, bool detectEncodingFromByteOrderMarks) : this(stream, Encoding.UTF8, detectEncodingFromByteOrderMarks, 0x400)
		{
		}
 
		public LatentStreamReader(Stream stream, Encoding encoding) : this(stream, encoding, true, 0x400)
		{
		}
 
		public LatentStreamReader(string path, bool detectEncodingFromByteOrderMarks) : this(path, Encoding.UTF8, detectEncodingFromByteOrderMarks, 0x400)
		{
		}
 
		public LatentStreamReader(string path, Encoding encoding) : this(path, encoding, true, 0x400)
		{
		}
 
		public LatentStreamReader(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks) : this(stream, encoding, detectEncodingFromByteOrderMarks, 0x400)
		{
		}
 
		public LatentStreamReader(string path, Encoding encoding, bool detectEncodingFromByteOrderMarks) : this(path, encoding, detectEncodingFromByteOrderMarks, 0x400)
		{
		}
 
		public LatentStreamReader(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize)
		{
			if ((stream == null) || (encoding == null))
			{
				throw new ArgumentNullException((stream == null) ? "stream" : "encoding");
			}
			if (!stream.CanRead)
			{
				throw new ArgumentException("Stream was not readable.");
			}
			if (bufferSize <= 0)
			{
				throw new ArgumentOutOfRangeException("bufferSize", "Positive number required.");
			}
			this.Init(stream, encoding, detectEncodingFromByteOrderMarks, bufferSize);
		}
 
		public LatentStreamReader(string path, Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize)
		{
			if ((path == null) || (encoding == null))
			{
				throw new ArgumentNullException((path == null) ? "path" : "encoding");
			}
			if (path.Length == 0)
			{
				throw new ArgumentException("Empty path name is not legal.");
			}
			if (bufferSize <= 0)
			{
				throw new ArgumentOutOfRangeException("bufferSize", "Positive number required.");
			}
			Stream stream1 = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 0x1000);
			this.Init(stream1, encoding, detectEncodingFromByteOrderMarks, bufferSize);
		}
		#endregion

		#region Public Methods 
		public override void Close()
		{
			this.Dispose(true);
		}
 
		public void DiscardBufferedData()
		{
			this.byteLen = 0;
			this.charLen = 0;
			this.charPos = 0;
			this.decoder = this.encoding.GetDecoder();
			this._isBlocked = false;
		}

		public override int Peek()
		{
			if (this.stream == null)
			{
				ERR_ReaderClosed();
			}
			if ((this.charPos != this.charLen) || (!this._isBlocked && (this.ReadBuffer() != 0)))
			{
				this.AttendPendingLinefeed();
			}
			if ((this.charPos != this.charLen) || (!this._isBlocked && (this.ReadBuffer() != 0)))
			{
				return this.charBuffer[this.charPos];
			}
			return -1;
		}
 
		public override int Read()
		{
			if (this.stream == null)
			{
				ERR_ReaderClosed();
			}
			if ((this.charPos == this.charLen) && (this.ReadBuffer() == 0))
			{
				return -1;
			}
			this.AttendPendingLinefeed();
			if ((this.charPos == this.charLen) && (this.ReadBuffer() == 0))
			{
				return -1;
			}
			return this.charBuffer[this.charPos++];
		}
 
		public override int Read([In, Out] char[] buffer, int index, int count)
		{
			if (this.stream == null)
			{
				ERR_ReaderClosed();
			}
			if (buffer == null)
			{
				throw new ArgumentNullException("buffer", "Buffer cannot be null.");
			}
			if ((index < 0) || (count < 0))
			{
				throw new ArgumentOutOfRangeException((index < 0) ? "index" : "count", "Non-negative number required.");
			}
			if ((buffer.Length - index) < count)
			{
				throw new ArgumentException("Offset and length were out of bounds for the array or count is greater than the number of elements from index to the end of the source collection.");
			}
			this.AttendPendingLinefeed();
			int num1 = 0;
			bool flag1 = false;
			while (count > 0)
			{
				int num2 = this.charLen - this.charPos;
				if (num2 == 0)
				{
					num2 = this.ReadBuffer(buffer, index + num1, count, out flag1);
				}
				if (num2 == 0)
				{
					break;
				}
				if (num2 > count)
				{
					num2 = count;
				}
				if (!flag1)
				{
					Buffer.BlockCopy(this.charBuffer, this.charPos * 2, buffer, (index + num1) * 2, num2 * 2);
					this.charPos += num2;
				}
				num1 += num2;
				count -= num2;
				if (this._isBlocked)
				{
					break;
				}
			}
			return num1;
		}
		public override string ReadLine()
		{
			if (this.stream == null)
			{
				ERR_ReaderClosed();
			}
			if ((this.charPos == this.charLen) && (this.ReadBuffer() == 0))
			{
				return null;
			}
			this.AttendPendingLinefeed();
			if ((this.charPos == this.charLen) && (this.ReadBuffer() == 0))
			{
				return null;
			}
			StringBuilder builder1 = null;
			while (true)
			{
				lock(this)
				{
					int num1 = this.charPos;
					//This inner loop goes through all the characters in the charBuffer and sees if we have reached
					//a line terminator yet or not
					do
					{
						char ch1 = this.charBuffer[num1];
						if ((ch1 == '\r') || (ch1 == '\n'))
						{
							string text1;
							if (builder1 != null)
							{
								builder1.Append(this.charBuffer, this.charPos, (int) (num1 - this.charPos));
								text1 = builder1.ToString();
							}
							else
							{
								text1 = new string(this.charBuffer, this.charPos, num1 - this.charPos);
							}
							this.charPos = num1 + 1;
							if(ch1=='\r')
							{
								_IsLinefeedPending = true;
							}
							this.AttendPendingLinefeed();
							return ProcessBackspaceCharacters(text1);
						}
						num1++;
					} while (num1 < this.charLen);

					/* Code portion orginally designed to return whatever text is available.
					 * In this context, it would actually force the LatentStreamReader to wait (because
					 * of ReadBuffer() ),so we don't use it. Previous code either returns a line or waits
					 * until one is terminated.*/
					//However, appropriate if we got here because it is no longer possible to wait for
					//data from the stream.
					if (builder1 == null)
					{
						//If we haven't initialized the StringBuilder yet, do it now
						builder1 = new StringBuilder(num1 + 80);
					}
					//Append characters that we have gotten on this pass into the StringBuilder
					builder1.Append(this.charBuffer, this.charPos, num1);
					if (this.ReadBuffer() <= 0)
					{
						//ReadBuffer() failed to get new data. Return what we have.
						return ProcessBackspaceCharacters(builder1.ToString());
					}

					//At this point, the while(true) loop repeats, to get more characters, in that ultimate
					//search for the line terminator.
				}
			}
		}

		/// <summary>
		/// Takes a string of text and makes sure that backspace ('\b') is handled correctly.
		/// </summary>
		/// <param name="data">The string which has unhandled usage of '\b' in it</param>
		/// <returns>Returns a string that has had the backspaces handled</returns>
		private static string ProcessBackspaceCharacters(string data)
		{
			string d = (string)data.Clone();
			int bs_i = -1;
			bs_i = d.IndexOf('\b');
			while(bs_i >= 0)
			{
				if(bs_i == 0)
				{
					d = d.Remove(0,1);
				}
				else
				{
					d = d.Remove(bs_i-1,2);
				}
				bs_i = d.IndexOf('\b');
			}
			return d;
		}

		/// <summary>
		/// The only LatentStreamReader method that does not halt the current thread for more input.
		/// (Wouldn't that be an indefinite read operation? What purpose would that serve?)
		/// </summary>
		/// <returns></returns>
		public override string ReadToEnd()
		{
			int num1;
			if (this.stream == null)
			{
				ERR_ReaderClosed();
			}
			this.AttendPendingLinefeed();
			char[] chArray1 = new char[this.charBuffer.Length];
			StringBuilder builder1 = new StringBuilder(this.charBuffer.Length);
			while ((num1 = this.Read(chArray1, 0, chArray1.Length)) != 0)
			{
				builder1.Append(chArray1, 0, num1);
			}
			return builder1.ToString();
		}
		/// <summary>
		/// Instructs the latent stream reader, if it is waiting for more input, to continue without.
		/// </summary>
		public void Bailout()
		{
			this._Bailout = true;
		}
		#endregion

		#region Private Methods
		/// <summary>
		/// If there is more data on the char buffer, and the current (i.e. next to be handled)
		/// char is '\n', then eat it. If not, this.charPos will not be modified.
		/// No matter what, if unhandled char data is present, _IsLinefeedPending will be set to false.
		/// This method will not halt the current thread to wait for any data that it needs.
		/// </summary>
		protected void AttendPendingLinefeed()
		{
			if(this._IsLinefeedPending==false)
				return;	//No linefeed pending, so nothing to do here, move along

			if(this.charPos<this.charLen)
			{
				//We have data to examine. Lets see...
				if(this.charBuffer[this.charPos]=='\n')
				{
					//The pending linefeed was found, so effectively eat it, by advancing charPos
					this.charPos++;
				}
				//Regardless if linefeed was found or not, (we might have other data to 
				//let others deal with), indicate no that no linefeed is pending anymore
				this._IsLinefeedPending=false;
				return;
			}
			else
			{
				//Do data to even look at, so move along.
				return;
			}
		}
		protected bool OkayForImmediateRead()
		{
            if (stream == null) return false;
			if(this._IsNetWrapper)
			{
				bool b;
				try
				{
					b = ((System.Net.Sockets.NetworkStream)this.stream).DataAvailable;
				}
				catch(System.ObjectDisposedException e)
				{
					throw new System.IO.IOException("Cannot read from NetworkStream, it has been disposed.",e);
				}

				return b;
			}
			else if(this._IsPSWrapper)
			{
				int x;
				x = ((System.IO.ParsedStream)stream).Peek();
				return (x>=0);
			}
			else
				return true;
		}

        private delegate void VOIDulus();
		protected void WaitForSafeRead()
		{
            if (OkayForImmediateRead())
                return;

            System.Threading.EventWaitHandle waitHandle = new EventWaitHandle(false,EventResetMode.ManualReset);
            VOIDulus d = delegate()
            {
                System.Threading.Thread.Sleep(333);
                while (!OkayForImmediateRead())
                {
                    System.Threading.Thread.Sleep(333);
                }
                waitHandle.Set();
            };

            if (OkayForImmediateRead())
                return;
            IAsyncResult arslt = d.BeginInvoke(null, null);
            waitHandle.WaitOne();
            d.EndInvoke(arslt);
		}

		private static bool BytesMatch(byte[] buffer, byte[] compareTo)
		{
			for (int num1 = 0; num1 < compareTo.Length; num1++)
			{
				if (buffer[num1] != compareTo[num1])
				{
					return false;
				}
			}
			return true;
		}

		private void CompressBuffer(int n)
		{
			Buffer.BlockCopy(this.byteBuffer, n, this.byteBuffer, 0, this.byteLen - n);
			this.byteLen -= n;
		}
 
		private void DetectEncoding()
		{
			if (this.byteLen >= 2)
			{
				this._detectEncoding = false;
				bool flag1 = false;
				if ((this.byteBuffer[0] == 0xfe) && (this.byteBuffer[1] == 0xff))
				{
					this.encoding = new UnicodeEncoding(true, true);
					this.decoder = this.encoding.GetDecoder();
					this.CompressBuffer(2);
					flag1 = true;
				}
				else if ((this.byteBuffer[0] == 0xff) && (this.byteBuffer[1] == 0xfe))
				{
					this.encoding = new UnicodeEncoding(false, true);
					this.decoder = this.encoding.GetDecoder();
					this.CompressBuffer(2);
					flag1 = true;
				}
				else if (((this.byteLen >= 3) && (this.byteBuffer[0] == 0xef)) && ((this.byteBuffer[1] == 0xbb) && (this.byteBuffer[2] == 0xbf)))
				{
					this.encoding = Encoding.UTF8;
					this.decoder = this.encoding.GetDecoder();
					this.CompressBuffer(3);
					flag1 = true;
				}
				else if (this.byteLen == 2)
				{
					this._detectEncoding = true;
				}
				if (flag1)
				{
					this._maxCharsPerBuffer = this.encoding.GetMaxCharCount(this.byteBuffer.Length);
					this.charBuffer = new char[this._maxCharsPerBuffer];
				}
			}
		}

		protected override void Dispose(bool disposing)
		{
            this._Bailout = true;
			if (disposing && (this.stream != null))
			{
                lock (this.stream)
                {
                    this.stream.Close();
                }
			}
			if (this.stream != null)
			{
                lock (this.stream)
                {
                    this.encoding = null;
                    this.decoder = null;
                    this.byteBuffer = null;
                    this.charBuffer = null;
                }
                this.stream = null;
				this.charPos = 0;
				this.charLen = 0;
			}
			base.Dispose(disposing);
		}
 
		private void Init(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize)
		{
			this.stream = stream;
			this.encoding = encoding;
			this.decoder = encoding.GetDecoder();
			if (bufferSize < 0x80)
			{
				bufferSize = 0x80;
			}
			this.byteBuffer = new byte[bufferSize];
			this._maxCharsPerBuffer = encoding.GetMaxCharCount(bufferSize);
			this.charBuffer = new char[this._maxCharsPerBuffer];
			this.byteLen = 0;
			this._detectEncoding = detectEncodingFromByteOrderMarks;
			this._preamble = encoding.GetPreamble();
			this._checkPreamble = this._preamble.Length > 0;
			this._isBlocked = false;
			this._IsLinefeedPending = false;
			if(this.stream.GetType()==typeof(System.Net.Sockets.NetworkStream)
				||
				this.stream.GetType().IsSubclassOf(typeof(System.Net.Sockets.NetworkStream)))
			{
				this._IsNetWrapper = true;
				this._IsPSWrapper = false;
			}
			else
			{
				this._IsNetWrapper = false;
				if(this.stream.GetType()==typeof(System.IO.ParsedStream)
					||
					this.stream.GetType().IsSubclassOf(typeof(System.IO.ParsedStream)))
				{
					this._IsPSWrapper = true;
				}
				else
				{
					this._IsPSWrapper = false;
				}
			}
		}

		private int ReadBuffer()
		{
			this.charLen = 0;
			this.byteLen = 0;
			this.charPos = 0;
			while (true)
			{
				if(this.OkayForImmediateRead())
				{
					this.byteLen = this.stream.Read(this.byteBuffer, 0, this.byteBuffer.Length);
				}
				else
				{
					this.WaitForSafeRead();
                    if (_Bailout == true || stream == null)
                        return -1;
					this.byteLen = this.stream.Read(this.byteBuffer, 0, this.byteBuffer.Length);
				}
				if (this.byteLen == 0)
				{
					return this.charLen;
				}
				this._isBlocked = this.byteLen < this.byteBuffer.Length;
				if (this._checkPreamble && (this.byteLen >= this._preamble.Length))
				{
					this._checkPreamble = false;
					if (LatentStreamReader.BytesMatch(this.byteBuffer, this._preamble))
					{
						this._detectEncoding = false;
						this.CompressBuffer(this._preamble.Length);
					}
				}
				if (this._detectEncoding && (this.byteLen >= 2))
				{
					this.DetectEncoding();
				}
				this.charLen += this.decoder.GetChars(this.byteBuffer, 0, this.byteLen, this.charBuffer, this.charLen);
				if (this.charLen != 0)
				{
					return this.charLen;
				}
			}
		}
 
		private int ReadBuffer(char[] userBuffer, int userOffset, int desiredChars, out bool readToUserBuffer)
		{
			this.charLen = 0;
			this.byteLen = 0;
			this.charPos = 0;
			int num1 = 0;
			readToUserBuffer = desiredChars >= this._maxCharsPerBuffer;
			while (true)
			{
				this.byteLen = this.stream.Read(this.byteBuffer, 0, this.byteBuffer.Length);
				if (this.byteLen == 0)
				{
					return num1;
				}
				this._isBlocked = this.byteLen < this.byteBuffer.Length;
				if (this._detectEncoding && (this.byteLen >= 2))
				{
					this.DetectEncoding();
					readToUserBuffer = desiredChars >= this._maxCharsPerBuffer;
				}
				if (this._checkPreamble && (this.byteLen >= this._preamble.Length))
				{
					this._checkPreamble = false;
					if (LatentStreamReader.BytesMatch(this.byteBuffer, this._preamble))
					{
						this._detectEncoding = false;
						this.CompressBuffer(this._preamble.Length);
						readToUserBuffer = desiredChars >= this._maxCharsPerBuffer;
					}
				}
				this.charPos = 0;
				if (readToUserBuffer)
				{
					num1 += this.decoder.GetChars(this.byteBuffer, 0, this.byteLen, userBuffer, userOffset + num1);
					this.charLen = 0;
				}
				else
				{
					num1 = this.decoder.GetChars(this.byteBuffer, 0, this.byteLen, this.charBuffer, num1);
					this.charLen += num1;
				}
				if (num1 != 0)
				{
					return num1;
				}
			}
		}
		#endregion

		#region Public Properties
		public virtual Stream BaseStream
		{
			get
			{
				return this.stream;
			}
		}
 
		public virtual Encoding CurrentEncoding
		{
			get
			{
				return this.encoding;
			}
		}
		#endregion

		#region Other
		public static new readonly StreamReader Null;
		internal static void ERR_ReaderClosed()
		{
			throw new ObjectDisposedException(null, "Cannot read from a closed TextReader.");
		}
		#endregion

		private class NullLatentStreamReader : LatentStreamReader
		{
			public override Encoding CurrentEncoding
			{
				get
				{
					return Encoding.Unicode;
				}
			}
 
			public override Stream BaseStream
			{
				get
				{
					return Stream.Null;
				}
			}
 
			public override string ReadToEnd()
			{
				return string.Empty;
			}
 
			public override string ReadLine()
			{
				return null;
			}
 
			public override int Read(char[] buffer, int index, int count)
			{
				return 0;
			}
			public override int Read()
			{
				return -1;
			}
 
			public override int Peek()
			{
				return -1;
			}
 
			public NullLatentStreamReader()
			{
			}
 

		}

		
		#region Old Code
		//		private System.IO.StreamReader _BaseReader;
		//		private bool _Bailout;
		//
		//		#region Constructors
		//		/// <summary>
		//		/// The default constructor for LatentStreamReader. Not in use.
		//		/// </summary>
		//		private LatentStreamReader()
		//		{
		//		}
		//
		//		/// <summary>
		//		/// Intializes an instance of LatentStreamReader.
		//		/// </summary>
		//		public LatentStreamReader(System.IO.Stream stream, bool detectEncodingFromByteOrderMarks)
		//			:this(stream,System.Text.Encoding.UTF8,detectEncodingFromByteOrderMarks)
		//		{
		//		}
		//
		//		/// <summary>
		//		/// Intializes an instance of LatentStreamReader.
		//		/// </summary>
		//		public LatentStreamReader(System.IO.Stream stream, System.Text.Encoding encoding)
		//			:this(stream,encoding,true)
		//		{
		//		}
		//
		//		/// <summary>
		//		/// Intializes an instance of LatentStreamReader.
		//		/// </summary>
		//		public LatentStreamReader(System.IO.Stream stream, System.Text.Encoding encoding, bool detectEncodingFromByteOrderMarks)
		//			:this(stream,encoding,detectEncodingFromByteOrderMarks,0x400)
		//		{
		//		}
		//
		//		/// <summary>
		//		/// Intializes an instance of LatentStreamReader.
		//		/// </summary>
		//		public LatentStreamReader(System.IO.Stream stream, System.Text.Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize)
		//			:this(new System.IO.StreamReader(stream,encoding,detectEncodingFromByteOrderMarks,bufferSize))
		//		{	
		//		}
		//
		//		/// <summary>
		//		/// Intializes an instance of LatentStreamReader.
		//		/// </summary>
		//		public LatentStreamReader(System.IO.StreamReader baseReader)
		//		{
		//			_BaseReader = baseReader;
		//		}
		//		#endregion
		//
		//		#region StreamReader Stuff
		//		/// <summary>
		//		/// Closes this LatentStreamReader and releases any resources associated with it
		//		/// </summary>
		//		public override void Close()
		//		{
		//			_BaseReader.Close();
		//		}
		//
		//		/// <summary>
		//		/// Reads a byte from the underlying stream without consuming it. If no data exists, the LatentStreamReader causes the current thread to wait until there is.
		//		/// </summary>
		//		/// <returns>Returns a byte read from the underlying stream.</returns>
		//		public override int Peek()
		//		{
		//			int x = _BaseReader.Peek();
		//			
		//			if(x<=0)
		//			{this.WaitForByte();}
		//
		//			return _BaseReader.Peek();
		//		}
		//		/// <summary>
		//		/// Reads a byte from the underlying stream. If no data exists, the LatentStreamReader causes the current thread to wait until there is.
		//		/// </summary>
		//		/// <returns>Returns a byte read from the underlying stream.</returns>
		//		public override int Read()
		//		{
		//			int x = _BaseReader.Peek();
		//			
		//			if(x<=0)
		//			{this.WaitForByte();}
		//
		//			return _BaseReader.Read();
		//		}
		//
		//		/// <summary>
		//		/// Reads characters from the underlying stream into the given buffer. If no data exists, the LatentStreamReader causes the current thread to wait until there is.
		//		/// </summary>
		//		/// <param name="buffer">The buffer to read the characters into</param>
		//		/// <param name="index">The starting index on the buffer to write to</param>
		//		/// <param name="count">The number of characters to try and read from the underlying stream</param>
		//		/// <returns>Returns the number of characters that were actually read from the underlying stream</returns>
		//		public override int Read(char[] buffer, int index, int count)
		//		{
		//			int x = _BaseReader.Peek();
		//			
		//			if(x<=0)
		//			{this.WaitForByte();}
		//
		//			return _BaseReader.Read(buffer,index,count);
		//		}
		//
		//		/// <summary>
		//		/// Reads characters from the underlying stream into the given buffer. If no data exists, the LatentStreamReader causes the current thread to wait until there is.
		//		/// </summary>
		//		/// <param name="buffer">The buffer to read the characters into</param>
		//		/// <param name="index">The starting index on the buffer to write to</param>
		//		/// <param name="count">The number of characters to try and read from the underlying stream</param>
		//		/// <returns>Returns the number of characters that were actually read from the underlying stream</returns>
		//		public override int ReadBlock(char[] buffer, int index, int count)
		//		{
		//			int x = _BaseReader.Peek();
		//			
		//			if(x<=0)
		//			{this.WaitForByte();}
		//
		//			return _BaseReader.ReadBlock(buffer,index,count);
		//		}
		//
		//		/// <summary>
		//		/// Reads a line of text from the underlying stream. If a complete line of text is not available, the LatentStreamReader causes the current thread to wait until there is.
		//		/// </summary>
		//		/// <returns>Returns a line of text read from the underlying stream.</returns>
		//		public override string ReadLine()
		//		{
		//			return WaitForReadLine();
		//		}
		//
		//		/// <summary>
		//		/// Reads all characters currently available from the underlying stream.
		//		/// </summary>
		//		/// <returns></returns>
		//		public override string ReadToEnd()
		//		{
		//			return _BaseReader.ReadToEnd();
		//		}
		//		#endregion
		//
		//		/// <summary>
		//		/// This function is used to wait until the underlying stream has at least 1 non-null byte
		//		/// available to be read.
		//		/// </summary>
		//		private void WaitForByte()
		//		{
		//			do
		//			{
		//				System.Threading.Thread.Sleep( System.TimeSpan.FromSeconds(0.01) );
		//			} while(_BaseReader.Peek()<=0 && _Bailout==false);
		//			ResetBailout();
		//		}
		//
		//		/// <summary>
		//		/// This function is used to wait until the underlying stream has a complete line of
		//		/// text available to read.
		//		/// </summary>
		//		/// <returns>Returns the line of text successfully read from the underlying stream.</returns>
		//		private string WaitForReadLine()
		//		{
		//			string s="";
		//			int i=0;
		//			string c;
		//			do
		//			{
		//				_BaseReader.BaseStream.Flush();
		//				System.Threading.Thread.Sleep( System.TimeSpan.FromSeconds(0.1) );
		//				i = _BaseReader.Read();
		//				if(i<0)
		//					continue;
		//				c = System.Text.Encoding.Default.GetString(new byte[] {(byte)i});
		//				s = s + c;
		//
		//				if(s==null)
		//					continue;
		//				if(s.EndsWith(System.Environment.NewLine))
		//					break;
		//				if(s.LastIndexOf('\n')>=0)
		//					break;
		//				if(this._Bailout==true)
		//					break;
		//			} while(true);
		//			ResetBailout();
		//			if(s.EndsWith(System.Environment.NewLine))
		//				return s.Substring(0,s.Length - System.Environment.NewLine.Length);
		//			if(s.EndsWith("\r"))
		//				return s.Substring(0,s.Length - "\r".Length);
		//			if(s.EndsWith("\r\n"))
		//				return s.Substring(0,s.Length - "\n\r".Length);
		//			if(s.EndsWith("\r"))
		//				return s.Substring(0,s.Length - "\r".Length);
		//			return s;
		//		}
		//		/// <summary>
		//		/// This function is used to tell the LatentTextReader to stop waiting for data from the
		//		/// underlying stream and to return whatever is available at the moment.
		//		/// </summary>
		//		internal void BailoutNow()
		//		{
		//			this._Bailout = true;
		//		}
		//		/// <summary>
		//		/// This function simply resets the Bailout state of the thread so that future wait operations
		//		/// will act normally.
		//		/// </summary>
		//		private void ResetBailout()
		//		{
		//			this._Bailout = false;
		//		}
		#endregion
	}
}